"""
Redis数据库工具类
提供Redis连接、增删改查操作以及支持占位符操作
"""

from typing import Any, List, Dict, Optional, Union


class RedisUtils:
    """
    Redis数据库操作工具类
    支持连接管理、增删改查操作和占位符操作
    
    注意：此类需要redis库支持
    安装方式：
    pip install redis
    """

    def __init__(self, host: str = 'localhost', port: int = 6379, 
                 password: str = None, db: int = 0):
        """
        初始化Redis连接参数
        
        Args:
            host: Redis主机地址，默认为localhost
            port: Redis端口，默认为6379
            password: Redis密码（可选）
            db: 数据库编号，默认为0
        """
        self.host = host
        self.port = port
        self.password = password
        self.db = db
        self.connection = None

    def connect(self) -> 'RedisUtils':
        """
        建立Redis连接
        
        Returns:
            RedisUtils实例，支持链式调用
        """
        try:
            # 尝试导入redis
            try:
                import redis
            except ImportError:
                raise ImportError("需要安装redis库。请运行: pip install redis")
                
            self.connection = redis.Redis(
                host=self.host,
                port=self.port,
                password=self.password,
                db=self.db,
                decode_responses=True
            )
            
            # 测试连接
            self.connection.ping()
            return self
        except Exception as e:
            raise Exception(f"连接Redis数据库失败: {str(e)}")

    def disconnect(self) -> None:
        """
        关闭Redis连接
        """
        if self.connection:
            self.connection.close()
            self.connection = None

    def set_value(self, key: str, value: Any, expire: Optional[int] = None) -> bool:
        """
        设置键值对
        
        Args:
            key: 键
            value: 值
            expire: 过期时间（秒），可选
            
        Returns:
            设置是否成功
        """
        if not self.connection:
            raise Exception("Redis未连接")
            
        try:
            import redis
            return self.connection.set(key, value, ex=expire)
        except redis.RedisError as e:
            raise Exception(f"设置键值对失败: {str(e)}")

    def get_value(self, key: str) -> Optional[str]:
        """
        获取键对应的值
        
        Args:
            key: 键
            
        Returns:
            键对应的值，如果键不存在则返回None
        """
        if not self.connection:
            raise Exception("Redis未连接")
            
        try:
            import redis
            return self.connection.get(key)
        except redis.RedisError as e:
            raise Exception(f"获取键值失败: {str(e)}")

    def delete_key(self, key: str) -> int:
        """
        删除键
        
        Args:
            key: 键
            
        Returns:
            删除的键数量
        """
        if not self.connection:
            raise Exception("Redis未连接")
            
        try:
            import redis
            return self.connection.delete(key)
        except redis.RedisError as e:
            raise Exception(f"删除键失败: {str(e)}")

    def exists_key(self, key: str) -> bool:
        """
        检查键是否存在
        
        Args:
            key: 键
            
        Returns:
            键是否存在
        """
        if not self.connection:
            raise Exception("Redis未连接")
            
        try:
            import redis
            return self.connection.exists(key) > 0
        except redis.RedisError as e:
            raise Exception(f"检查键存在性失败: {str(e)}")

    def set_hash(self, name: str, mapping: Dict[str, Any]) -> bool:
        """
        设置哈希表
        
        Args:
            name: 哈希表名称
            mapping: 哈希表映射
            
        Returns:
            设置是否成功
        """
        if not self.connection:
            raise Exception("Redis未连接")
            
        try:
            import redis
            return self.connection.hset(name, mapping=mapping) >= 0
        except redis.RedisError as e:
            raise Exception(f"设置哈希表失败: {str(e)}")

    def get_hash(self, name: str, key: str = None) -> Union[str, Dict[str, str]]:
        """
        获取哈希表或哈希表中的字段值
        
        Args:
            name: 哈希表名称
            key: 字段名称（可选），如果不提供则返回整个哈希表
            
        Returns:
            如果提供了key，返回字段值；否则返回整个哈希表
        """
        if not self.connection:
            raise Exception("Redis未连接")
            
        try:
            import redis
            if key:
                return self.connection.hget(name, key)
            else:
                return self.connection.hgetall(name)
        except redis.RedisError as e:
            raise Exception(f"获取哈希表失败: {str(e)}")

    def delete_hash_field(self, name: str, *keys: str) -> int:
        """
        删除哈希表中的字段
        
        Args:
            name: 哈希表名称
            keys: 要删除的字段名
            
        Returns:
            删除的字段数量
        """
        if not self.connection:
            raise Exception("Redis未连接")
            
        try:
            import redis
            return self.connection.hdel(name, *keys)
        except redis.RedisError as e:
            raise Exception(f"删除哈希表字段失败: {str(e)}")

    def execute_command(self, command: str, *args) -> Any:
        """
        执行Redis命令
        
        Args:
            command: Redis命令
            args: 命令参数
            
        Returns:
            命令执行结果
        """
        if not self.connection:
            raise Exception("Redis未连接")
            
        try:
            import redis
            return self.connection.execute_command(command, *args)
        except redis.RedisError as e:
            raise Exception(f"执行Redis命令失败: {str(e)}")

    def keys(self, pattern: str = "*") -> List[str]:
        """
        查找所有符合给定模式的键
        
        Args:
            pattern: 模式，默认为"*"（匹配所有键）
            
        Returns:
            符合模式的键列表
        """
        if not self.connection:
            raise Exception("Redis未连接")
            
        try:
            import redis
            return self.connection.keys(pattern)
        except redis.RedisError as e:
            raise Exception(f"查找键失败: {str(e)}")

    def flush_db(self) -> bool:
        """
        清空当前数据库
        
        Returns:
            清空是否成功
        """
        if not self.connection:
            raise Exception("Redis未连接")
            
        try:
            import redis
            return self.connection.flushdb()
        except redis.RedisError as e:
            raise Exception(f"清空数据库失败: {str(e)}")

    def __enter__(self) -> 'RedisUtils':
        """
        上下文管理器入口，自动连接Redis
        """
        self.connect()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        """
        上下文管理器出口，自动关闭Redis连接
        """
        self.disconnect()